﻿/*
 * @Author: ws.s 
 * @Date: 2021-10-25 10:24:06 
 * @Last Modified by: ws.s
 * @Last Modified time: 2021-10-25 14:49:13
 */
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;

/// 更新记录
/// V 1.1.0 Last Modified time: 2021-10-25 10:52:58
/// 重构之前版本的ImageFLyTo,可以以更多种方式控制效果
/// 


/// <summary>
/// 可以让图片从一个位置飞到另外一个位置，代替粒子系统使用。
/// 比如获得金币效果，飞往对应位置。
/// </summary>
[RequireComponent(typeof(BhvEasyPool))]
public class UIImageFlyTo : MonoBehaviour
{
    BhvEasyPool bhvEasyPool;
    private Vector3 startPosition;
    private Vector3 targetPosition;
    public GameObject targetObject;

    public int emitCount = 10;
    [Header("===== 时间和间隔 =====")]
    [Tooltip("发射间隔时间")]
    public float emitTime = 0.05f;
    [Tooltip("过渡时间，动画基本时间长度")]
    public float duration = 1.0f;
    [Tooltip("移动延迟时间")]
    public float moveDelayTime = 0.3f;

    [Header("===== 范围 =====")]
    public float radiusMin = 80f;
    public float radiusMax = 100f;

    public bool burstMode = true;

    /// <summary>
    ///( GameObject gameObject, int cur, int max)=>{}
    /// </summary>
    public System.Action<GameObject, int, int> onParticleEmit;

    /// <summary>
    /// 飞向目标的移动方式
    /// </summary>
    public enum SpawnType
    {
        Liner,
        Explode,
        Drop,
    }

    /// <summary>
    /// 飞向目标的移动方式
    /// </summary>
    public enum MoveType
    {
        /// <summary>线性移动 </summary>
        Liner,
        /// <summary>跳跃移动 </summary>
        JumpTo,

    }

    public SpawnType spawnType = SpawnType.Liner;
    public MoveType moveType = MoveType.JumpTo;

    private void Awake()
    {
        bhvEasyPool = GetComponent<BhvEasyPool>();
    }

#if UNITY_EDITOR

    [EditorButton]
    private void TestEmit()
    {
        Emit();
    }

#endif

    /// <summary>
    /// 发射器发射
    /// </summary>
    /// <param name="endPos">终点坐标</param>
    /// <param name="count">发射数量</param>
    /// <param name="duration">持续时间</param>
    public void Emit(Vector3 endPos, int count = 0, float duration = 0f)
    {
        if (!this.isActiveAndEnabled) return;
        targetPosition = endPos;
        StartCoroutine(FlyToDelay(count, duration));

    }

    /// <summary>
    /// 发射器发射
    /// </summary>
    /// <param name="count">发射数量</param>
    /// <param name="duration">发射时间</param>
    public void Emit(int count = 0, float duration = 0)
    {
        this.startPosition = this.transform.position;
        Emit(targetObject ? targetObject.transform.position : Vector3.zero, count, duration);
    }

    /// <summary>
    ///  发射器发射(自定义)
    /// </summary>
    /// <param name="startPos">开始坐标</param>
    /// <param name="endPos">结束坐标</param>
    /// <param name="count">发射数量</param>
    /// <param name="duration">发射时间</param>
    /// <param name="callback">发射准备函数 ( GameObject gameObject, int cur, int max)=>{} </param>
    public void Emit(Vector3 startPos, Vector3 endPos, int count = 0, float duration = 0, System.Action<GameObject, int, int> callback = null)
    {
        if (!this.isActiveAndEnabled) return;

        this.onParticleEmit = callback;
        this.startPosition = startPos;
        this.targetPosition = endPos;
        this.emitCount = count;
        this.duration = duration;
        StartCoroutine(FlyToDelay(count, duration));
    }

    private IEnumerator FlyToDelay(int count = 0, float duration = 0)
    {
        if (duration == 0) duration = this.duration;
        if (count == 0) count = this.emitCount;
        for (int i = 0; i < count; i++)
        {
            var obj = bhvEasyPool.Get();
            obj.transform.position = this.startPosition;
            onParticleEmit?.Invoke(obj, i, count);

            var originScale = obj.transform.localScale;
            obj.transform.localScale = Vector3.zero;
            obj.transform.SetAsLastSibling();//调整显示顺序

            if (emitTime > 0)
            {
                yield return new WaitForSeconds(emitTime);
            }

            float radius = Random.Range(radiusMin, radiusMax);
            var seq = DOTween.Sequence();
            switch (this.spawnType)
            {
                case SpawnType.Liner:
                    obj.transform.localScale = originScale;
                    break;
                case SpawnType.Explode:
                    float deltaAngle = Mathf.Deg2Rad * 360f / count;
                    float ox = Mathf.Cos(deltaAngle * i) * radius;
                    float oy = Mathf.Sin(deltaAngle * i) * radius;
                    float rndDuration = 0.3f + Random.Range(-0.2f, 0.2f);
                    obj.transform.localScale = Vector3.zero;
                    obj.transform.DOScale(originScale, rndDuration).SetEase(Ease.OutBack);
                    seq.Append(obj.transform.DOMove(this.startPosition + new Vector3(ox, oy, 0), rndDuration));
                    break;
                case SpawnType.Drop:
                    deltaAngle = Mathf.Deg2Rad * 90f / count;
                    ox = Mathf.Cos(deltaAngle * i) * radius;
                    oy = Mathf.Sin(deltaAngle * i) * radius;
                    rndDuration = 0.3f + Random.Range(-0.2f, 0.2f);
                    obj.transform.localScale = Vector3.zero;
                    obj.transform.DOScale(Vector3.one, rndDuration).SetEase(Ease.OutBack);
                    seq.Append(obj.transform.DOJump(this.startPosition + new Vector3(ox, oy, 0), 300, 1, rndDuration).SetEase(Ease.OutBounce));
                    break;
                default:
                    obj.transform.localScale = originScale;
                    break;
            }

            switch (this.moveType)
            {
                case MoveType.JumpTo:
                    seq.Append(obj.transform.DOJump(targetPosition, Random.Range(-300, 300), 1, duration).SetDelay(moveDelayTime));
                    break;
                default:
                    seq.Append(obj.transform.DOMove(targetPosition, duration).SetDelay(moveDelayTime));
                    break;
            }
            seq.Insert(duration + moveDelayTime + 0.3f, obj.transform.DOScale(Vector3.zero, 0.3f));
            seq.SetId(obj);
            seq.AppendCallback(() =>
            {
                DOTween.Kill(obj);
                obj.transform.localScale = originScale;
                bhvEasyPool.Put(obj);
            });

        }

    }

}
